
// Promise支持链式调用; catch


const PENDING = "PENDING"
const FULLFILLED = "FULLFILLED"
const REJECTED = "REJECTED"

function MyPromise(flag, constructor){
    this.flag = flag
    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    this.onFullfilledCallbacks = new Array()
    this.onRejectedCallbacks = new Array()   

    const resolve = () =>{
       if(this.state === PENDING){
           console.log('resolve:', this.onFullfilledCallbacks, this.flag)
            this.state = FULLFILLED
            this.onFullfilledCallbacks.forEach(fn => {
               fn()
            })
       }
    }

    const reject = () => {
        if(this.state === PENDING){
            this.state = REJECTED
            console.log('reject', this.onRejectedCallbacks, this.flag)
            this.onRejectedCallbacks.forEach(fn => {
                fn()
            })
        }
    }

    try {
        constructor(resolve, reject)
    } catch (error) {
        reject(error)
    }
   
}

MyPromise.prototype.then = function(onFullfilled, onRejected) {
    onFullfilled = typeof onFullfilled === 'function'? onFullfilled : v => v
    onRejected = typeof onRejected === 'function'? onRejected : err => { throw err }
    // then 通过返回promise支持链表调用
    let promise2 = new MyPromise(this.flag + 1, (resolve2, reject2)=>{
        if(this.state === PENDING){
            this.onFullfilledCallbacks.push(()=>{
               queueMicrotask(()=>{
                    let x = onFullfilled(this.value)
                    resolvePromise(promise2, x, resolve2, reject2)
               })
            })
            this.onRejectedCallbacks.push(()=>{
                queueMicrotask(()=>{

                    // 这里的try-catch很重要； 
                    // 当形参onRejected没有定义时抛出错误
                    // 此时会将错误传递下去
                    // 传递到最后被Promise.prototype.catch捕获
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve2, reject2)
                    } catch (error) {
                        reject2(error)
                    }
                })
            })
        }else if(this.state === FULLFILLED){
           queueMicrotask(()=>{
                let x = onFullfilled(this.value)
                resolvePromise(promise2, x, resolve2, reject2)
           })
        }else if(this.state === REJECTED){
            queueMicrotask(()=>{
                let x  = onRejected(this.reason)
                resolvePromise(promise2, x, resolve2, reject2)
            })
        }
        
    })
    return promise2
}

MyPromise.prototype.catch = function(onRejected){
    this.then(null, onRejected )
}

MyPromise.prototype.finally = function(){}

const resolvePromise = function(promise2, x, resolve, reject){
    if(promise2 === x) new TypeError("")
    if(x instanceof MyPromise){
        x.then()
    }else{
       resolve(x)
    }
}

const p = new MyPromise(1, (resolve, reject)=>{
    setTimeout(()=>{
        reject(1234)
    }, 1000)
}).then((value)=>{
    console.log("Promise then 1", value)
    return 2
}).then((value)=>{
    console.log("Promise then 2", value)
    return 3
}).then((value)=>{
    console.log("Promise then 3", value)
}).catch((reason)=>{
    console.log("Promise catch", reason)
})



